/**
 * @file 	 mbSlave_demo.c
 * @brief
 * @author 	 wenbo
 * @version  1.0
 * @date 	 2023-03-22
 *
 * @copyright Copyright (c) 2023  YGL
 *
 */
#include "mbSlave_demo.h"
#include "mbrtu.h"
#include "fmb_port.h"
#include "xp_lpuart.h"


#define LOGI println


/**
 * 应用层调用 mbSlave_demo_init() 初始化并运行 modbus 协议栈, 当前文件仅是对Lite机型HMI对接HMI使用演示,
 * 不同应用需要参考此文件,在相应的工程目录中创建独立的从机实例并可选的实现指定寄存器回调接口
 */

/**
 * @brief       定义 HMI 寄存器数据结构
 */
input_reg_map_t input_reg_map = { 0 };
hold_reg_map_t hold_reg_map = { 0 };
coils_reg_map_t coils_reg_map = { 0 };


static void modbus_demo_task(void* arg);	// 接收到新数据后被唤醒并执行协议栈接口解析数据
void mb_app_demo_task(void* arg);	// 构造虚拟数据用于 HMI 展示
static aos_sem_t mb_sem;	// 用于接收到数据后唤醒处理线程

/**
 * @brief       mbSlave 任务创建(应用层唯一调用接口)
 */
void mbSlave_demo_init(void)
{
	aos_task_new("freemodbus_task", modbus_demo_task, NULL, 4096);
	aos_task_new("mb_app_demo_task", mb_app_demo_task, NULL, 4096);
}
/**
 * @brief       初始化时要注册的中断接收回调(生产信号量唤醒线程)
 */
static void recv_irq_callback(void)
{
	aos_sem_signal(&mb_sem);
}


// 根据实际应用,对部分寄存器设置回调,主机在读写时会回调以进行特殊处理(多个寄存器可注册同一个回调)
/***********************************************************************************/
void inputReg_0x0000_cb(USHORT regAddr, USHORT regData)
{
	LOGI("Input reg: 0x%04X = 0x%04X", regAddr, regData);
}
void inputReg_0x0001_cb(USHORT regAddr, USHORT regData)
{
	LOGI("Input reg: 0x%04X = 0x%04X", regAddr, regData);
}

void holdReg_0x0000_0x0002_cb(USHORT regAddr, USHORT regData, BOOL isWrite)
{
	LOGI("Hold reg: 0x%04X = 0x%04X %c", regAddr, regData, isWrite ? 'W' : 'R');
}
void holdReg_0x0003_0x0004_cb(USHORT regAddr, USHORT regData, BOOL isWrite)
{
	LOGI("Hold reg: 0x%04X = 0x%04X %c", regAddr, regData, isWrite ? 'W' : 'R');
}

void coilsReg_0x0000_0x0002_cb(USHORT regAddr, BOOL isON, BOOL isWrite)
{
	LOGI("Coils reg: 0x%04X = %d %c", regAddr, isON ? 1 : 0, isWrite ? 'W' : 'R');

	if (isWrite) {
		coils_reg_map.washMode.fast = 0;
		coils_reg_map.washMode.normal = 0;
		coils_reg_map.washMode.clean = 0;

		if (0x0000 == regAddr && isON) {
			LOGI("washMode.fast");
		}
		else if (0x0001 == regAddr && isON) {
			LOGI("washMode.normal");
		}
		else if (0x0002 == regAddr && isON) {
			LOGI("washMode.clean");
		}
	}
}
void coilsReg_0x0003_0x0010_cb(USHORT regAddr, BOOL isON, BOOL isWrite)
{
	LOGI("Coils reg: 0x%04X = %d %c", regAddr, isON ? 1 : 0, isWrite ? 'W' : 'R');
}
/***********************************************************************************/


/**
 * @brief       modbus 协议栈任务,负责初始化串口硬件,对接收缓存的数据进行解析,轮询发送缓冲中数据
 * @param[in]	arg                 ...
 */
static void modbus_demo_task(void* arg)
{
	aos_sem_new(&mb_sem, 0);

#define DEMO_PORT       4
#define DEMO_SLAVEID    1

	// 1. 创建从机实例(必须)
	/***********************************************************************************/
	void* ctx = mbSlave_creat(DEMO_SLAVEID, DEMO_PORT, 115200, 0);

	// 2. 映射使用到的各类寄存器(注意某些寄存器可能为U32,但映射时的数量仅用U16计算)(必须)
	/***********************************************************************************/
	LOGI("Input reg size: %d(byte)", sizeof(input_reg_map));
	mbSlave_mapping_input_reg(ctx, (uint16_t*) &input_reg_map, 0x0000, sizeof(input_reg_map) / sizeof(uint16_t));
	LOGI("Hold reg size: %d(byte)", sizeof(hold_reg_map));
	mbSlave_mapping_hold_reg(ctx, (uint16_t*) &hold_reg_map, 0x0000, sizeof(hold_reg_map) / sizeof(uint16_t));
	LOGI("Coils reg size: %d(byte)", sizeof(coils_reg_map));
	mbSlave_mapping_coils_reg(ctx, (uint8_t*) &coils_reg_map, 0x0000, sizeof(coils_reg_map) * 8);


	// 3. 注册需要关注的寄存器的读写回调(非必须)
	/***********************************************************************************/
	mbSlave_register_input_reg_callback(ctx, 0x0000, inputReg_0x0000_cb);
	mbSlave_register_input_reg_callback(ctx, 0x0001, inputReg_0x0001_cb);

	mbSlave_register_hold_reg_callback(ctx, 0x0000, holdReg_0x0000_0x0002_cb);
	mbSlave_register_hold_reg_callback(ctx, 0x0001, holdReg_0x0000_0x0002_cb);
	mbSlave_register_hold_reg_callback(ctx, 0x0002, holdReg_0x0000_0x0002_cb);
	mbSlave_register_hold_reg_callback(ctx, 0x0003, holdReg_0x0003_0x0004_cb);
	mbSlave_register_hold_reg_callback(ctx, 0x0004, holdReg_0x0003_0x0004_cb);

	mbSlave_register_coils_reg_callback(ctx, 0x0000, coilsReg_0x0000_0x0002_cb);
	mbSlave_register_coils_reg_callback(ctx, 0x0001, coilsReg_0x0000_0x0002_cb);
	mbSlave_register_coils_reg_callback(ctx, 0x0002, coilsReg_0x0000_0x0002_cb);

	mbSlave_register_coils_reg_callback(ctx, 0x0003, coilsReg_0x0003_0x0010_cb);
	mbSlave_register_coils_reg_callback(ctx, 0x0004, coilsReg_0x0003_0x0010_cb);
	mbSlave_register_coils_reg_callback(ctx, 0x0005, coilsReg_0x0003_0x0010_cb);
	mbSlave_register_coils_reg_callback(ctx, 0x0006, coilsReg_0x0003_0x0010_cb);
	mbSlave_register_coils_reg_callback(ctx, 0x0007, coilsReg_0x0003_0x0010_cb);
	mbSlave_register_coils_reg_callback(ctx, 0x0008, coilsReg_0x0003_0x0010_cb);
	mbSlave_register_coils_reg_callback(ctx, 0x0009, coilsReg_0x0003_0x0010_cb);
	mbSlave_register_coils_reg_callback(ctx, 0x000A, coilsReg_0x0003_0x0010_cb);
	mbSlave_register_coils_reg_callback(ctx, 0x000B, coilsReg_0x0003_0x0010_cb);
	mbSlave_register_coils_reg_callback(ctx, 0x000C, coilsReg_0x0003_0x0010_cb);
	mbSlave_register_coils_reg_callback(ctx, 0x000D, coilsReg_0x0003_0x0010_cb);
	mbSlave_register_coils_reg_callback(ctx, 0x000E, coilsReg_0x0003_0x0010_cb);
	mbSlave_register_coils_reg_callback(ctx, 0x000F, coilsReg_0x0003_0x0010_cb);
	mbSlave_register_coils_reg_callback(ctx, 0x0010, coilsReg_0x0003_0x0010_cb);

	// 4. 注册接收空闲中断回调,当前demo中用于发出信号量激活任务运行(建议)
	register_recv_irq_callback(DEMO_PORT, recv_irq_callback);

	if (!ctx) {
		LOGI("mbSlave_creat failed");
		return;
	}

	for (;;) {
		aos_sem_wait(&mb_sem, AOS_WAIT_FOREVER);

		/* 检测接收环形buffer是否有新数据 */
		uint8_t* pData;
		uint16_t size;
		if (pop_from_rx_ringbuffer(DEMO_PORT, &pData, &size)) {

			eMBRTU_Process(ctx, pData, size);

			//LOGI("Recv %d, 0x%02X ... 0x%02X\r\n", size, pData[0], pData[size - 1]);
		}

		// 将通过push_to_tx_ringbuffer()的数据实际发送出去(DMA忙的时候可能发送失败,这里需要重新生产信号量进行后续轮询发送)
		if (!flush_tx_ringbuffer(DEMO_PORT)){
			aos_msleep(1);
			aos_sem_signal(&mb_sem);
		}
	}
	mbSlave_distory(ctx);
}
void mb_app_demo_task(void* arg)
{
	while (1) {
		// 单量统计页面：今日单量
		input_reg_map.today.washFastOrders++;
		input_reg_map.today.washNormalOrders++;
		input_reg_map.today.washCleanOrders++;
		input_reg_map.today.todayOrders++;

		// 单量统计页面：月总单量
		for (size_t i = 0; i < 12; i++)
		{
			input_reg_map.monthTotalOrders[i] += 2;
		}
		
		// 单量统计页面：选中某月查看月详细单量
		for (size_t i = 0; i < 12; i++)
		{
			// 当月各种模式的单量统计
			input_reg_map.monthOrders[i].washNormalOrders_curr++;
			input_reg_map.monthOrders[i].washFastOrders_curr++;
			input_reg_map.monthOrders[i].washCleanOrders_curr++;
			input_reg_map.monthOrders[i].monthOrders_curr = 
			input_reg_map.monthOrders[i].washNormalOrders_curr + 
			input_reg_map.monthOrders[i].washFastOrders_curr + 
			input_reg_map.monthOrders[i].washCleanOrders_curr;

			for (size_t j = 0; j < 31; j++)
			{
				// 选中某个月(i)后每天(j)的各种模式单量
				input_reg_map.monthOrders[i].dayOrders[j].washFastOrders = i * j;
				input_reg_map.monthOrders[i].dayOrders[j].washNormalOrders = i * j + 1;
				input_reg_map.monthOrders[i].dayOrders[j].washCleanOrders = i * j + 2;
				input_reg_map.monthOrders[i].dayOrders[j].todayOrders 
				=  	input_reg_map.monthOrders[i].dayOrders[j].washFastOrders + 
					input_reg_map.monthOrders[i].dayOrders[j].washNormalOrders + 
					input_reg_map.monthOrders[i].dayOrders[j].washCleanOrders;
			}
		}
		
		// 首页：用电量,用水量...
		hold_reg_map.totalElectricity += 0.5f;
		hold_reg_map.totalWater += 0.5f;
		hold_reg_map.pressure++;
		hold_reg_map.totalOrders += 10;

		aos_msleep(1000);
	}
}
